﻿
// Client.cpp : 定义应用程序的类行为。
//

#include "stdafx.h"
#include "Client.h"
#include "MainDlg.h"
#pragma comment(lib, "Crypt32.lib")
#include <cryptdlg.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CMainApp

BEGIN_MESSAGE_MAP(CMainApp, CWinApp)
	ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()


// CMainApp 构造

CMainApp::CMainApp()
{
	// 支持重新启动管理器
	m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;

	// TODO: 在此处添加构造代码，
	// 将所有重要的初始化放置在 InitInstance 中
}


// 唯一的一个 CMainApp 对象

CMainApp theApp;
void Test()
{
    HCRYPTPROV hProv = NULL; 
    HCRYPTKEY hSignKey = NULL;
    HCRYPTKEY hExchangeKey = NULL;
    if(!::CryptAcquireContext(&hProv, _T("hxc"), MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
    {
        ::CryptAcquireContext(&hProv, _T("hxc"), MS_ENHANCED_PROV, PROV_RSA_FULL,
            CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET);
    }
    ::CryptGenKey(hProv, AT_SIGNATURE, 0x08000000 | CRYPT_EXPORTABLE, &hSignKey);

    PCCERT_CONTEXT pCertContext = NULL;

    // Encode certificate Subject
    CERT_NAME_BLOB SubjectIssuerBlob = {};
    LPCTSTR pszX500 = _T("CN=hxc");
    ::CertStrToName(X509_ASN_ENCODING, pszX500, CERT_X500_NAME_STR, NULL,
                SubjectIssuerBlob.pbData, &SubjectIssuerBlob.cbData, NULL);
    SubjectIssuerBlob.pbData = new BYTE[SubjectIssuerBlob.cbData];
    ::CertStrToName(X509_ASN_ENCODING, pszX500, CERT_X500_NAME_STR, NULL,
                SubjectIssuerBlob.pbData, &SubjectIssuerBlob.cbData, NULL);

    // Prepare algorithm structure for self-signed certificate
    CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm = {};
    SignatureAlgorithm.pszObjId = szOID_RSA_SHA1RSA;

    // Prepare Expiration date for self-signed certificate
    SYSTEMTIME EndTime;
    GetSystemTime(&EndTime);
    EndTime.wYear += 5;

    CRYPT_BIT_BLOB UsageInfo = {};
    UsageInfo.cbData = 1;
    BYTE Flags = CERT_DIGITAL_SIGNATURE_KEY_USAGE |
        CERT_DATA_ENCIPHERMENT_KEY_USAGE |
        CERT_KEY_ENCIPHERMENT_KEY_USAGE |
        CERT_KEY_AGREEMENT_KEY_USAGE;
    UsageInfo.pbData = &Flags;

    CERT_ENHKEY_USAGE CertEnhKeyUsage = {};
    CertEnhKeyUsage.cUsageIdentifier = 1;
    LPSTR UsageIdentifier[1] = {szOID_KP_EFS};
    CertEnhKeyUsage.rgpszUsageIdentifier = UsageIdentifier;
    
    CERT_EXTENSION CertExtension[2] = {};

    CertExtension[0].pszObjId = szOID_KEY_USAGE;
    ::CryptEncodeObject(X509_ASN_ENCODING, szOID_KEY_USAGE, &UsageInfo,
            CertExtension[0].Value.pbData, &CertExtension[0].Value.cbData);
    CertExtension[0].Value.pbData = new BYTE[CertExtension[0].Value.cbData];
    ::CryptEncodeObject(X509_ASN_ENCODING, szOID_KEY_USAGE, &UsageInfo,
        CertExtension[0].Value.pbData, &CertExtension[0].Value.cbData);

    CertExtension[1].pszObjId = szOID_ENHANCED_KEY_USAGE;
    ::CryptEncodeObject(X509_ASN_ENCODING, szOID_ENHANCED_KEY_USAGE, &CertEnhKeyUsage,
        CertExtension[1].Value.pbData, &CertExtension[1].Value.cbData);
    CertExtension[1].Value.pbData = new BYTE[CertExtension[1].Value.cbData];
    ::CryptEncodeObject(X509_ASN_ENCODING, szOID_ENHANCED_KEY_USAGE, &CertEnhKeyUsage,
        CertExtension[1].Value.pbData, &CertExtension[1].Value.cbData);


    CERT_EXTENSIONS Extensions = {2, CertExtension};

    CRYPT_KEY_PROV_INFO KeyProvInfo = {};
    KeyProvInfo.pwszContainerName = _T("hxc");
    KeyProvInfo.pwszProvName = NULL;
    KeyProvInfo.dwProvType = PROV_RSA_FULL;
    KeyProvInfo.dwFlags = CRYPT_MACHINE_KEYSET;
    KeyProvInfo.cProvParam = 0;
    KeyProvInfo.rgProvParam = NULL;
    KeyProvInfo.dwKeySpec = AT_SIGNATURE;

    pCertContext = CertCreateSelfSignCertificate(NULL, &SubjectIssuerBlob,
                    0, &KeyProvInfo, &SignatureAlgorithm, 0, &EndTime, &Extensions);

    HCERTSTORE hTempStore = ::CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, CERT_STORE_CREATE_NEW_FLAG, 0);
    //把证书添加到证书库中
    ::CertAddCertificateContextToStore(hTempStore, pCertContext, CERT_STORE_ADD_NEW, NULL);

    CRYPT_DATA_BLOB pfxData = {};
    ::PFXExportCertStoreEx(hTempStore, &pfxData, L"19900211", NULL, EXPORT_PRIVATE_KEYS);
    pfxData.pbData = new BYTE[pfxData.cbData];
    ::PFXExportCertStoreEx(hTempStore, &pfxData, L"19900211", NULL, EXPORT_PRIVATE_KEYS);

    HANDLE hFile = CreateFile(_T("D:\\Test.pfx"), GENERIC_READ | GENERIC_WRITE, 
        FILE_SHARE_READ | FILE_SHARE_WRITE, 
        NULL, CREATE_ALWAYS , 
        NULL, NULL);

    DWORD len = 0;
    ::WriteFile(hFile, pfxData.pbData, pfxData.cbData , &len, NULL); 

    ::CloseHandle(hFile);

    ::CertFreeCertificateContext(pCertContext);
    CertCloseStore(hTempStore, 0);
    delete[] SubjectIssuerBlob.pbData;
    delete[] pfxData.pbData;
    delete[] CertExtension[0].Value.pbData;
    delete[] CertExtension[1].Value.pbData;
    ::CryptDestroyKey(hSignKey);
    ::CryptDestroyKey(hExchangeKey);
    ::CryptAcquireContext(&hProv, _T("hxc"), nullptr, PROV_RSA_FULL,
                    CRYPT_DELETEKEYSET | CRYPT_MACHINE_KEYSET);
}

void Test1(void)
{
    HCERTSTORE hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER, L"MY");

    WCHAR szX500[] = _T("hxc");

    BYTE SerialNumber[] = "\x01\x62\x0b\x89\x82\x05\x06\x4d\xa3\x1d\x70\x6d\x81\xad\xa6\x2c";
    CRYPT_INTEGER_BLOB TagSerialNumber = {sizeof(GUID), SerialNumber};
    
    PCCERT_CONTEXT pContext = nullptr;
    while (true)
    {
        pContext = ::CertFindCertificateInStore(hStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
            0, CERT_FIND_SUBJECT_STR, szX500, pContext);
        if ((pContext == nullptr) || ::CertCompareIntegerBlob(&pContext->pCertInfo->SerialNumber, &TagSerialNumber))
            break;
    }

    if (pContext != nullptr)
    {
        CERT_INFO Cert = {};
        Cert.dwVersion = 2;

        // 2.SerialNumber
        GUID guid;
        HMODULE hDll = ::LoadLibrary(_T("Rpcrt4.dll"));
        void(__stdcall *pfn)(GUID*) = (void(__stdcall *)(GUID*))::GetProcAddress(hDll, "UuidCreate");
        pfn(&guid);
        FreeLibrary(hDll);
        Cert.SerialNumber.cbData = sizeof(GUID);
        Cert.SerialNumber.pbData = (BYTE*)&guid;

        // 3.Algorithm 
        Cert.SignatureAlgorithm.pszObjId = szOID_RSA_SHA1RSA; 
        Cert.SignatureAlgorithm.Parameters.cbData = 0; 

        // 4.Issuer. Encode the Issuer name with ASN.1 ,reference MSDN source 
        Cert.Issuer.cbData = pContext->pCertInfo->Issuer.cbData; 
        Cert.Issuer.pbData = pContext->pCertInfo->Issuer.pbData; 

        // 5.UTCTime .Process the Time of cert. SystemTimeToFileTime 
        SYSTEMTIME SysTime; 
        GetSystemTime(&SysTime); 
        SystemTimeToFileTime( &SysTime , &Cert.NotBefore); 

        SysTime.wYear += 10; 
        SystemTimeToFileTime( &SysTime , &Cert.NotAfter);

        // 6.subject
        TCHAR *Cert_Subject_Name =_T("CN=hxc-d133130a71d");

        ::CertStrToName(X509_ASN_ENCODING, Cert_Subject_Name, CERT_X500_NAME_STR, NULL,
            Cert.Subject.pbData, &Cert.Subject.cbData, NULL);

        Cert.Subject.pbData = new BYTE[Cert.Subject.cbData];

        ::CertStrToName(X509_ASN_ENCODING, Cert_Subject_Name, CERT_X500_NAME_STR, NULL,
            Cert.Subject.pbData, &Cert.Subject.cbData, NULL);


        //7.PublicKey
        HCRYPTPROV hProvSubject = NULL;
        HCRYPTKEY hSignKey = NULL;
        if(!::CryptAcquireContext(&hProvSubject, _T("hxc"), MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
        {
            ::CryptAcquireContext(&hProvSubject, _T("hxc"), MS_ENHANCED_PROV, PROV_RSA_FULL,
                CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET);
        }
        ::CryptGenKey(hProvSubject, AT_SIGNATURE, 0x08000000 | CRYPT_EXPORTABLE, &hSignKey);
        PCERT_PUBLIC_KEY_INFO PubKeyBuf = nullptr;
        DWORD PubKeyLen = 0;
        ::CryptExportPublicKeyInfo(hProvSubject, AT_SIGNATURE, X509_ASN_ENCODING ,NULL,&PubKeyLen);

        PubKeyBuf = (PCERT_PUBLIC_KEY_INFO)new BYTE[PubKeyLen];

        ::CryptExportPublicKeyInfo( hProvSubject, AT_SIGNATURE,
            X509_ASN_ENCODING ,PubKeyBuf,&PubKeyLen ); 

        Cert.SubjectPublicKeyInfo = *PubKeyBuf; 

        // Extendsion 
        Cert.cExtension = 0; 
        Cert.rgExtension = NULL; 
        Cert.IssuerUniqueId.cbData = 0 ; 
        Cert.SubjectUniqueId.cbData = 0; 

        //Make Certificate 
        CRYPT_ALGORITHM_IDENTIFIER algId;
        BYTE paraData[16];
        paraData[0] = 0x05; paraData[1] = 0x00;

        algId.pszObjId = szOID_RSA_SHA1RSA;
        algId.Parameters.cbData = 2;
        algId.Parameters.pbData = paraData;

        PBYTE pCertOut;
        DWORD CertLen;
        DWORD dwKeyType = 0;
        BOOL bMustFreeProvIssuer = FALSE;
        HCRYPTPROV hProvIssuer = NULL;
        ::CryptAcquireCertificatePrivateKey(pContext, 0, nullptr, &hProvIssuer, &dwKeyType, &bMustFreeProvIssuer);
        ::CryptSignAndEncodeCertificate(hProvIssuer, dwKeyType, 
            X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, (void*)&Cert, &algId, 
            NULL,NULL, &CertLen);

        pCertOut = new BYTE[CertLen];

        CryptSignAndEncodeCertificate(hProvIssuer, dwKeyType, 
            X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED, (void*)&Cert, &algId, 
            NULL,pCertOut, &CertLen);

        PCCERT_CONTEXT pNewCert = ::CertCreateCertificateContext(X509_ASN_ENCODING, pCertOut, CertLen);

        CRYPT_KEY_PROV_INFO KeyProvInfo = {};
        KeyProvInfo.pwszContainerName = _T("hxc");
        KeyProvInfo.pwszProvName = NULL;
        KeyProvInfo.dwProvType = PROV_RSA_FULL;
        KeyProvInfo.dwFlags = CRYPT_MACHINE_KEYSET;
        KeyProvInfo.cProvParam = 0;
        KeyProvInfo.rgProvParam = NULL;
        KeyProvInfo.dwKeySpec = AT_SIGNATURE;
        ::CertSetCertificateContextProperty(pNewCert, CERT_KEY_PROV_INFO_PROP_ID, 0, &KeyProvInfo);

        HCERTSTORE hTempStore = ::CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, CERT_STORE_CREATE_NEW_FLAG, 0);
        //把证书添加到证书库中
        ::CertAddCertificateContextToStore(hTempStore, pNewCert, CERT_STORE_ADD_NEW, NULL);

        CRYPT_DATA_BLOB pfxData = {};
        ::PFXExportCertStoreEx(hTempStore, &pfxData, L"19900211", NULL, EXPORT_PRIVATE_KEYS);
        pfxData.pbData = new BYTE[pfxData.cbData];
        ::PFXExportCertStoreEx(hTempStore, &pfxData, L"19900211", NULL, EXPORT_PRIVATE_KEYS);

        HANDLE hFile = CreateFile(_T("D:\\Test.pfx"), GENERIC_READ | GENERIC_WRITE, 
            FILE_SHARE_READ | FILE_SHARE_WRITE, 
            NULL, CREATE_ALWAYS , 
            NULL, NULL);

        DWORD len = 0;
        ::WriteFile(hFile, pfxData.pbData, pfxData.cbData, &len, NULL); 

        ::CloseHandle(hFile);
        ::CertFreeCertificateContext(pNewCert);
        CertCloseStore(hTempStore, 0);
        if (bMustFreeProvIssuer)
            ::CryptReleaseContext(hProvIssuer, 0);
        ::CryptAcquireContext(&hProvSubject, _T("hxc"), nullptr, PROV_RSA_FULL,
            CRYPT_DELETEKEYSET | CRYPT_MACHINE_KEYSET);
        delete[] pfxData.pbData;
        delete[] PubKeyBuf;
        delete[] pCertOut;
    }
    ::CertFreeCertificateContext(pContext);
    ::CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
}

// CMainApp 初始化

BOOL CMainApp::InitInstance()
{
	// 如果一个运行在 Windows XP 上的应用程序清单指定要
	// 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式，
	//则需要 InitCommonControlsEx()。否则，将无法创建窗口。
	INITCOMMONCONTROLSEX InitCtrls;
	InitCtrls.dwSize = sizeof(InitCtrls);
	// 将它设置为包括所有要在应用程序中使用的
	// 公共控件类。
	InitCtrls.dwICC = ICC_WIN95_CLASSES;
	InitCommonControlsEx(&InitCtrls);

	CWinApp::InitInstance();

	AfxEnableControlContainer();

	// 创建 shell 管理器，以防对话框包含
	// 任何 shell 树视图控件或 shell 列表视图控件。

    hxc::SI =  new hxc::_SocketInitializer;
    hxc::SI->Initialize();

    CMainDlg *pdlg =  new CMainDlg();
    pdlg->Create(CMainDlg::IDD);
    this->m_pMainWnd = pdlg;

    /*sUDP = hxc::CSocketBase::CreateSocket<hxc::CUDPSocket>(pdlg);
    sTCP = hxc::CSocketBase::CreateSocket<hxc::CTCPSocket>(pdlg);

    sockaddr_in addr = {};
    addr.sin_family = AF_INET;
    addr.sin_addr.S_un.S_addr = INADDR_ANY;
    addr.sin_port = htons(27051);
    if (SOCKET_ERROR == sUDP->Bind(&addr))
    {
        ::MessageBox(::GetActiveWindow(), _T("UDP套接字绑定27051端口失败。"), _T("Client"), MB_OK | MB_ICONERROR);
        delete sUDP;
        delete pdlg;
        return FALSE;
    }
    for (int i = 0; i < 10; i++)
        sUDP->Receive();

    addr.sin_port = htons(27050);
    if (SOCKET_ERROR == sTCP->Bind(&addr))
    {
        ::MessageBox(::GetActiveWindow(), _T("TCP套接字绑定27050端口失败。"), _T("Client"), MB_OK | MB_ICONERROR);
        sUDP->Shutdown(SD_BOTH);
        delete sUDP;
        delete sTCP;
        delete pdlg;
        return FALSE;
    }
    sTCP->Listen(SOMAXCONN);
    sTCP->PostAcceptOperation();*/

    HOSTENT *pHostName = ::gethostbyname("liyuqihxc.gicp.net");
    if (pHostName->h_addrtype == AF_INET)
    {
        sockaddr_in addr = {};
        addr.sin_family = AF_INET;
        addr.sin_addr.S_un.S_addr = INADDR_ANY;
        hxc::CUDPSocket *s = hxc::CSocketBase::CreateSocket<hxc::CUDPSocket>(pdlg);
        s->Bind(&addr);
        addr.sin_port = htons(27051);
        addr.sin_addr.S_un.S_addr = inet_addr("192.168.1.140");//*(u_long*)pHostName->h_addr_list[0];
        while (1)
        {
            s->SendTo((LPBYTE)"Client\n", 8, &addr, 0);
            Sleep(3000);
        }
    }
    //this->m_pMainWnd->ShowWindow(this->m_nCmdShow);
	return FALSE;
}

int CMainApp::ExitInstance()
{
    //delete sUDP;
    //delete sTCP;
    delete this->m_pMainWnd;
    hxc::SI->Free();
    return 0;
}